package de.zainodis.triplog.ui;

import android.app.ActionBar;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.SearchView;
import android.widget.Toast;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.model.LatLng;

import org.json.JSONException;

import java.util.Date;

import de.zainodis.triplog.R;
import de.zainodis.triplog.data.DataProvider;
import de.zainodis.triplog.data.JsonParser;
import de.zainodis.triplog.data.LocationEntry;
import de.zainodis.triplog.data.TripEntry;
import de.zainodis.triplog.data.WeatherEntry;
import de.zainodis.triplog.util.DateTimeUtils;

/**
 * First step of planning a trip: Shows the user a map where he can pick his destination for the trip.
 */
//TODO show an entry screen first that explains to the user what is going to happen next (i.e. pick a location)
public class TripWizardLocation extends GoogleMapsActivity implements IAlertDialogHost {

    //TODO let the user chose a location via long press on the map
    private static final String TAG = "TripWizardLocation";
    private static final String TAG_DIALOG = "Dialog";

    private static final String BUNDLE_LOCATION_ENTRY = "LocationEntry";
    private static final String BUNDLE_SEARCHBAR_INPUT = "SearchbarInput";


    //Cached so we can restore it in case of a config change event
    private LocationEntry locationEntry = null;
    //Cached so we can restore it in case of a config change event
    private String searchBarInput = null;
    //Cache so we can hide/show on demand
    private MenuItem menuItemActionDone = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_trip_wizard_location);
        ActionBar bar = getActionBar();
        if (bar != null) {
            //Hide title and app logo for now so we have more space
            bar.setDisplayShowTitleEnabled(false);
            bar.setDisplayShowHomeEnabled(false);
        }
        if (savedInstanceState != null) {
            //Restore previous instance
            locationEntry = savedInstanceState.getParcelable(BUNDLE_LOCATION_ENTRY);
            searchBarInput = savedInstanceState.getString(BUNDLE_SEARCHBAR_INPUT);
        }

        //Reload the weather if available
        displayWeatherForecast(locationEntry);

        setUpMapIfNeeded();
    }

    @Override
    protected void onResume() {
        super.onResume();
        setUpMapIfNeeded();
    }

    @Override
    public void onOk() {
        new AsyncTask<Void, Void, Void>() {

            @Override
            protected Void doInBackground(Void... params) {
                if (!TripWizardLocation.this.isFinishing()) {
                    //TODO showing old data despite starting a new trip
                    // User confirmed creation of new trip despite warning
                    DataProvider.endAllOngoingTrips(TripWizardLocation.this);
                    //Create a new trip
                    TripEntry trip = new TripEntry();
                    trip.setStart(DateTimeUtils.toDbDateString(new Date()));
                    trip.setLocation(locationEntry);
                    //Persist the trip to database
                    trip.createOrUpdate(TripWizardLocation.this);
                    //Update cache
                    DataProvider.setCurrentTrip(trip);
                    Intent intent = new Intent(TripWizardLocation.this, DashboardActivity.class);
                    startActivity(intent);
                    //Finish this one, so the user can't come back
                    finish();
                }
                return null;
            }
        }.execute();

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        switch (id) {
            case R.id.action_done:
                //Check if a location has been picked, if yes wrap up the wizard and move to the ongoing trip dashboard
                if (getLatLng() != null) {
                    //TODO this should be done on a background thread
                    if (TripEntry.queryForOpen(this, true) != null) {
                        NewTripWarning newFragment = NewTripWarning.newInstance(0);
                        newFragment.show(getFragmentManager(), TAG_DIALOG);
                    } else {
                        //We got all the remaining code in on OK so forward
                        onOk();
                    }

                }
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if (menu != null) {
            menuItemActionDone = menu.findItem(R.id.action_done);
            if (menuItemActionDone != null) {
                //Hide until the user has selected a destination
                if (getLatLng() == null) {
                    menuItemActionDone.setVisible(false);
                } else {
                    menuItemActionDone.setVisible(true);
                }
            }
        }
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the options menu from XML
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.trip_wizard_location, menu);

        // Get the SearchView and set the searchable configuration
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        final SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
        // Assumes current activity is the searchable activity
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        // Do not iconify the widget; expand it by default
        searchView.setIconifiedByDefault(false);
        searchView.setSearchableInfo(
                searchManager.getSearchableInfo(getComponentName()));
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextChange(String newText) {
                //Cache the input value
                searchBarInput = newText;
                return true;
            }

            @Override
            public boolean onQueryTextSubmit(String query) {
                //Check if there is an input, if not don't do anything
                if (query != null && !query.isEmpty()) {
                    //Hide the keyboard
                    searchView.clearFocus();
                    //Hide the weather view
                    LinearLayout view = (LinearLayout) findViewById(R.id.weather_forecast);
                    view.setVisibility(View.GONE);
                    //User has completed search input by pressing search button
                    new DisplayLocationAndWeatherTask().execute(query);
                }
                return true;
            }
        });

        //Update searchbar input if available
        if (searchBarInput != null && !searchBarInput.isEmpty()) {
            searchView.setQuery(searchBarInput, false);
        }

        return true;
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        //Save lat/lon so we can restore it upon config change sa well as the weather
        if (getLatLng() != null) {
            if (locationEntry != null) {
                outState.putParcelable(BUNDLE_LOCATION_ENTRY, locationEntry);
            }

            if (searchBarInput != null && !searchBarInput.isEmpty()) {
                outState.putString(BUNDLE_SEARCHBAR_INPUT, searchBarInput);
            }
        }
    }

    @Override
    protected boolean setMarker(LatLng position, String title) {
        boolean result = super.setMarker(position, title);

        //Enable action item done if available
        if (menuItemActionDone != null && result) {
            menuItemActionDone.setVisible(true);
            invalidateOptionsMenu();
        }
        return result;
    }


    /**
     * Loads the location provided by the user into the map.
     */
    private class DisplayLocationAndWeatherTask extends AsyncTask<String, Void, LocationEntry> {

        @Override
        protected LocationEntry doInBackground(String... locationName) {
            String location = locationName[0];
            //Request weather data from JSON for given location (one day only for now)
            String jsonResponse = JsonParser.requestWeatherForecast(location, getString(R.string.pref_value_metric), "1");
            LocationEntry locationEntry = null;
            try {
                locationEntry = JsonParser.getWeatherDataFromJson(TripWizardLocation.this, jsonResponse, location);
            } catch (JSONException e) {
                Log.e(TAG, "Failed to parse weather and location from OWM using JSON", e);
            }
            return locationEntry;
        }

        @Override
        protected void onPostExecute(LocationEntry location) {
            if (location == null) {
                Toast.makeText(getBaseContext(), getString(R.string.location_not_found), Toast.LENGTH_SHORT).show();
                return;
            } else {
                //Cache the location entry so we can later retrieve it if need be
                locationEntry = location;
            }

            setLatLng(new LatLng(locationEntry.getLatitude(), locationEntry.getLongitude()));
            //Set a marker for the target destination
            setMarker(getLatLng(), location.getCityName());

            float maxZoom = getMap().getMaxZoomLevel();
            getMap().animateCamera(CameraUpdateFactory.newLatLngZoom(getLatLng(), maxZoom / 2));

            displayWeatherForecast(locationEntry);
        }
    }

    /**
     * Displays the weather for the currently selected destination.
     * This checks the given WeatherEntry for null, so you can safely pass in null as well. Of course in that case it won't actually display any forecast.
     *
     * @param location contains the weather forecast to display.
     */
    private void displayWeatherForecast(LocationEntry location) {
        if (location == null) {
            return;
        }

        if (location.getWeatherEntries().size() > 0) {
            WeatherEntry weather = location.getWeatherEntries().get(0);
            //Show the weather forecast for today
            LinearLayout view = (LinearLayout) findViewById(R.id.weather_forecast);
            view.setBackgroundColor(getResources().getColor(R.color.white_translucent));
            WeatherForecastAdapter.populateView(weather, view, TripWizardLocation.this, null);
            view.setVisibility(View.VISIBLE);
        }
    }
}
